/*
 * openGL.h
 *
 *  Created on: 06.10.2011
 *      Author: ignacio
 */
#ifndef CL_CHARACTER_H_
#define CL_CHARACTER_H_

#include "clanlib.h"
#include "Character.h"
//typedef neurignacio::Vector3 Vector;
#include "flock.h" // For Parent<Type>
#include "path.h"
#include "Group.h"

namespace neurignacio{
/*
 * *******************
 * CL_BaseProperties *
 * *******************
 */
	class CL_BaseProperties
	{
	#define VECTOR_ZERO Vector3(0,0,0)
	#define VECTOR_SIZE_GRAPHICCONTEXT Vector3(graphicContext->get_width(),graphicContext->get_height(),0)
	protected:
		Vector3 worldSize; // From -x..x, -y..y
		Vector3 windowSize; // From (0,0)
	protected:
		void init();
	public:
		CL_GraphicContext* graphicContext;
	public:
		CL_BaseProperties() : graphicContext(0), worldSize(VECTOR_SIZE_GRAPHICCONTEXT), windowSize() {}
		CL_BaseProperties(CL_GraphicContext &gc, const Vector3 &world_size=VECTOR_ZERO) : graphicContext(&gc), worldSize(world_size), windowSize() {init();}
		CL_BaseProperties(CL_GraphicContext &gc, const int &worldWidth, const int &worldHeight) : graphicContext(&gc), worldSize(Vector3(worldWidth, worldHeight,0)) {init();}
		CL_BaseProperties(const CL_BaseProperties& properties) : worldSize(properties.worldSize), windowSize(properties.windowSize), graphicContext(properties.graphicContext) {}
		CL_BaseProperties& operator=(const CL_BaseProperties& other)
			{if (this!=&other) {worldSize=other.worldSize; windowSize=other.windowSize;graphicContext=other.graphicContext;} return *this;}
		bool isInsideGraphicContext(const Vector3& position)	{return position.x>=0 && position.x<windowSize.x && position.z >=0 && position.z < windowSize.y;} // position is (X,0,Z) -> windowPosition (X,Y,0)
		bool isInsideWorld(const Vector3& position) 			{return (position.x>=-(worldSize.x) && position.x<(worldSize.x) && position.z >=-worldSize.y && position.z < worldSize.y);}
		Vector3 getWindowPosition(const Vector3& position);
	};

/*
 * *********************
 * CL_SpriteProperties *
 * *********************
 */
	class CL_SpriteProperties : public CL_Sprite, public CL_BaseProperties
	{
	public:
		CL_SpriteProperties(void) : CL_Sprite(), CL_BaseProperties() {}
		CL_SpriteProperties(CL_GraphicContext &gc, const CL_StringRef &filename, const Vector3 &world_size=VECTOR_ZERO) : CL_Sprite(gc, filename), CL_BaseProperties(gc, world_size) {}
		CL_SpriteProperties(const CL_SpriteProperties& properties) : CL_Sprite(static_cast<CL_Sprite>(properties)), CL_BaseProperties(properties) {}
		CL_SpriteProperties& operator=(const CL_SpriteProperties& other)
			{if (this!=&other) {static_cast<CL_Sprite>(*this)=static_cast<CL_Sprite>(other); static_cast<CL_BaseProperties>(*this)=static_cast<CL_BaseProperties>(other);} return *this;}
		virtual void draw(const Vector3& position, const bool VERBOSITY=false);
		virtual void draw(const Location& location, const bool VERBOSITY=false) {set_angle(location.orientation*(-1)+HALF_PI_ANGLE); draw(location.position, VERBOSITY);}
	};

	class CL_Character : public Gluon, public CL_SpriteProperties
	// The CL_Character is a Gluon with added CL_Sprite properties
	// Contains information about the graphic representation and World Representation
	{

	public:
		CL_Character(void) :  Gluon(), CL_SpriteProperties() {}
		CL_Character(Gluon& gluon) : Gluon(gluon), CL_SpriteProperties() {}
		CL_Character(const CL_Character& character) : Gluon(static_cast<Gluon>(character)), CL_SpriteProperties(static_cast<CL_SpriteProperties>(character)) {}
		CL_Character& operator=(const CL_Character& other)
		{
			if (this!=&other) {static_cast<Gluon>(*this)=static_cast<Gluon>(other); static_cast<CL_SpriteProperties>(*this)=static_cast<CL_SpriteProperties>(other);} return *this;
		}
		CL_Character(CL_GraphicContext &gc, const CL_StringRef &filename, const Vector3 &world_size=VECTOR_ZERO) : Gluon(), CL_SpriteProperties(gc, filename, world_size) {}
		CL_Character(CL_GraphicContext &gc, const CL_StringRef &filename, const int &worldWidth, const int &worldHeight) : Gluon(), CL_SpriteProperties(gc, filename, Vector3(worldWidth, worldHeight,0)){}
		void draw(const bool VERBOSITY=false) {CL_SpriteProperties::draw(*this, VERBOSITY);}
		bool isInsideGraphicContext(void) {return CL_BaseProperties::isInsideGraphicContext(position);}
		bool isInsideWorld(void) {return CL_BaseProperties::isInsideWorld(position);}
		void bringBackToWorld();
		Vector3 getWindowPosition(void) {return CL_BaseProperties::getWindowPosition(position);}
	};

/*
 * *********
 * CL_Path *
 * *********
 */
	class CL_Path : public VectorPath, public CL_BaseProperties
	{
	protected:
		CL_Colorf color;
	public:
		CL_Path(void) : Path(), CL_BaseProperties(), color(CL_Colorf::grey) {}
		CL_Path(CL_GraphicContext &gc, const Vector3 &world_size=VECTOR_ZERO, const CL_Colorf &color=CL_Colorf::grey) : VectorPath(), CL_BaseProperties(gc, world_size), color(color) {}
		CL_Path(CL_GraphicContext &gc, const int &worldWidth, const int &worldHeight, const CL_Colorf &color=CL_Colorf::grey) : VectorPath(), CL_BaseProperties(gc, worldWidth, worldHeight), color(color) {}
		CL_Path(CL_GraphicContext &gc, VectorPath& path, const int &worldWidth, const int &worldHeight, const CL_Colorf &color=CL_Colorf::grey)
			: VectorPath(path), CL_BaseProperties(gc, worldWidth, worldHeight), color(color) {}
		void draw(void);
		Vector3 getWindowPosition(const Vector3& position);	// same as CL_Properties
	};
// Containers Definitions
	typedef BaseContainer<CL_Character> CL_CharacterContainer;	// Stores a set of CL_Characters
	typedef BasePointerContainer<CL_Character> CL_CharacterPointerContainer;

/*
 * ********************
 * CL_CharacterParent *
 * ********************
 */
	class CL_CharacterParent : public Parent<CL_Character>
	{
	public:
		bool parentVisibility;	// When false, parent is not drawn
	public:
		void draw(const bool VERBOSITY=false);
		void drawChildren(const bool VERBOSITY=false);
		bool isParentInsideGraphicContext(void) {parent->isInsideGraphicContext();}
		bool isParentInsideWorld(void) {return parent->isInsideWorld();}
		void bringParentBackToWorld(void) {parent->bringBackToWorld();}
		bool isChildrenInsideGraphicContext(void);
		bool isChildrenInsideWorld(void);
		void bringChildrenBackToWorld(void);
		bool isInsideGraphicContext(void) {return isParentInsideGraphicContext() && isChildrenInsideGraphicContext();}
		bool isInsideWorld(void) {return isParentInsideWorld() && isChildrenInsideWorld();}
		void bringBackToWorld(void) {bringParentBackToWorld(); bringChildrenBackToWorld();}
		Vector3 getWindowPosition(void) {return parent->getWindowPosition();}
	};
} // end namespace neurignacio



#endif /* CL_CHARACTER_H_ */
